home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 October
/
EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso
/
Aminet
/
mus
/
play
/
tracker_4_31.lzh
/
tracker
/
Arch
/
Sparc
/
audio.c
next >
Wrap
C/C++ Source or Header
|
1995-05-12
|
9KB
|
434 lines
/* sparc/audio.c
vi:ts=3 sw=3:
*/
/* $Id: audio.c,v 4.15 1995/05/12 20:40:46 espie Exp espie $
* $Log: audio.c,v $
* Revision 4.15 1995/05/12 20:40:46 espie
* Added frequency change.
*
* Revision 4.14 1995/05/12 13:52:39 espie
* New synchronization.
*
* Revision 4.13 1995/03/03 14:22:55 espie
* Fixed audio info bug.
*
* Revision 4.12 1995/02/26 23:07:14 espie
* solaris.
*
* Revision 4.11 1995/02/25 15:44:15 espie
* discard_buffer incorrect.
*
* Revision 4.10 1995/02/24 15:36:39 espie
* Finally fixed speed/sync/late start.
*
* Revision 4.9 1995/02/24 13:48:39 espie
* Fixed minor bug (interaction between pause and -sync).
*
* Revision 4.8 1995/02/24 13:43:52 espie
* Added -sync feature.
* In the absence of -sync, pause half a second at start to allow for
* data to accumulate in buffer first.
* Suppressed update freq on the fly since audioctl does not allow it.
*
* Revision 4.7 1995/02/23 22:41:45 espie
* Added # of bits.
*
* Revision 4.6 1995/02/23 16:42:27 espie
* Began conversion to `common' model.
*
* Revision 4.5 1995/02/23 13:52:30 espie
* primary, secondary -> primary+secondary, primary-secondary
* strike out 2 multiplications out of 4 !
*
* Revision 4.4 1995/02/21 17:57:55 espie
* Internal problem: RCS not working.
*
* Revision 4.3 1995/02/01 16:43:47 espie
* 23 bit samples.
*
* Revision 4.2 1994/01/13 09:19:08 espie
* Forgotten something.
*
* Revision 4.0 1994/01/11 18:16:36 espie
* New release.
*
* Revision 3.14 1993/12/04 16:12:50 espie
* BOOL -> boolean.
* Merged ss10/solaris.
* Merged support for solaris together.
* Fixed /16 bug.
* Corrected mix problem.
* restore stty.
* Sync pseudo call.
* Added update_frequency call, mostly unchecked
* Added finetune.
* Protracker commands.
*
* Revision 1.3 1992/11/17 15:38:00 espie
* discard_buffer() call for snappier interface calls.
* - Unified support for all sparcs.
* - moved down to level 2 io.
*/
#include "defs.h"
#include "extern.h"
#ifdef SOLARIS
#include <sys/audioio.h>
#else
#include <sun/audioio.h>
#endif
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stropts.h>
#include <signal.h>
#define DEFAULT_SET_MIX
#define DEFAULT_BUFFERS
#define NEW_OUTPUT_SAMPLES_AWARE
#define NEW_FUNCS
#include "Arch/common.c"
/* things that aren't defined in all sun/audioio.h */
#ifndef AUDIO_ENCODING_LINEAR
#define AUDIO_ENCODING_LINEAR (3)
#endif
#ifndef AUDIO_GETDEV
#define AUDIO_GETDEV _IOR(A, 4, int)
#endif
#ifndef AUDIO_DEV_UNKNOWN
#define AUDIO_DEV_UNKNOWN (0)
#endif
#ifndef AUDIO_DEV_AMD
#define AUDIO_DEV_AMD (1)
#endif
ID("$Id: audio.c,v 4.15 1995/05/12 20:40:46 espie Exp espie $")
LOCAL int audio;
LOCAL int written;
LOCAL int wait_samples;
LOCAL int tsync;
LOCAL int ADVANCE_TAGS= -1;
LOCAL struct audio_info ainfo, ainfo2;
/* set_synchronize(): pause the audio device at start of play,
* in order to accumulate enough samples before playing
*/
LOCAL void set_synchronize()
{
written = ainfo.play.eof;
if (!ainfo2.play.pause)
{
ainfo2.play.pause = TRUE;
ioctl(audio, AUDIO_SETINFO, &ainfo2);
/* number of samples to accumulate */
wait_samples = ainfo.play.sample_rate / 2;
}
else
wait_samples = 0;
}
LOCAL int possible[] = { 8000, 9600, 11025, 16000, 18900, 22050, 32000,
37800, 44100, 48000, 0};
int open_audio(f, s)
int f;
int s;
{
int type;
int basic;
#ifdef SOLARIS
audio_device_t dev;
audio = open("/dev/audio", O_WRONLY);
#else
audio = open("/dev/audio", O_WRONLY|O_NDELAY);
#endif
basic = 0;
if (audio == -1)
end_all("Error: could not open audio");
/* round frequency to acceptable value */
f = best_frequency(f, possible, 22050);
/* check whether we know about AUDIO_ENCODING_LINEAR */
AUDIO_INITINFO(&ainfo);
AUDIO_INITINFO(&ainfo2);
#ifdef SOLARIS
ioctl(audio, AUDIO_GETDEV, &dev);
if (strcmp(dev.name, "SUNW,dbri") != 0)
#else
if (ioctl(audio, AUDIO_GETDEV, &type) ||
type == AUDIO_DEV_UNKNOWN || type == AUDIO_DEV_AMD || basic)
#endif
{
/* not a new ss5/10/20 -> revert to base quality audio */
stereo = 0;
dsize = 1;
f = 8000;
ainfo.play.encoding = AUDIO_ENCODING_ULAW;
ainfo.play.channels = 1;
}
else
{
/* tentative set up */
stereo = s;
ainfo.play.precision = 16;
dsize = 2;
if (stereo)
ainfo.play.channels = 2;
else
ainfo.play.channels = 1;
/* try it */
ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
}
ainfo.play.sample_rate = f;
if (ioctl(audio, AUDIO_SETINFO, &ainfo) != 0)
/* didn't work: fatal problem */
end_all("Error: AUDIO_SETINFO");
idx = 0;
samples_max = ainfo.play.channels*ainfo.play.sample_rate;
buffer = (char *)malloc(dsize*samples_max);
buffer16 = (short *)buffer;
if (!buffer)
end_all("Error: could not allocate buffer");
set_synchronize();
return f;
}
void set_synchro(s)
int s;
{
tsync = s;
}
LOCAL int newfreq;
int update_frequency()
{
if (newfreq)
{
newfreq = 0;
samples_max = ainfo.play.channels * ainfo.play.sample_rate;
buffer = realloc(buffer, dsize * samples_max);
buffer16 = (short *)buffer;
return ainfo.play.sample_rate;
}
else
return 0;
/* the current implementation of the audio device does not allow
* output frequency change through /dev/audioctl
* -> this code is not needed
int oldfreq;
oldfreq = ainfo.play.sample_rate;
if (ioctl(audio, AUDIO_GETINFO, &ainfo) == 0)
{
if (oldfreq != ainfo.play.sample_rate)
{
samples_max = ainfo.play.channels * ainfo.play.sample_rate;
buffer = realloc(buffer, dsize * samples_max);
buffer16 = (short *)buffer;
return ainfo.play.sample_rate;
}
}
return 0;
*/
}
void audio_ui(c)
int c;
{
int i;
switch(c)
{
case '+':
if (audio & ainfo.play.encoding == AUDIO_ENCODING_LINEAR)
{
for (i = 0; ; i++)
if (possible[i] == ainfo.play.sample_rate)
break;
if (possible[i+1])
{
ainfo.play.sample_rate = possible[i+1];
if (ioctl(audio, AUDIO_SETINFO, &ainfo) == 0)
newfreq = 1;
}
}
break;
case '-':
if (audio & ainfo.play.encoding == AUDIO_ENCODING_LINEAR)
{
for (i = 0; ; i++)
if (possible[i] == ainfo.play.sample_rate)
break;
if (i)
{
ainfo.play.sample_rate = possible[i-1];
if (ioctl(audio, AUDIO_SETINFO, &ainfo) == 0)
newfreq = 1;
}
}
break;
default:
}
}
void output_samples(left, right, n)
int left, right, n;
{
switch(ainfo.play.encoding)
{
case AUDIO_ENCODING_LINEAR:
add_samples16(left, right, n);
break;
case AUDIO_ENCODING_ULAW:
buffer[idx++] = linear2ulaw((left + right) >> (n-14));
break;
default:
end_all("Error:Unknown audio encoding");
}
}
/* synchronize stuff with audio output */
struct tagged
{
struct tagged *next; /* simply linked list */
void (*f) P((GENERIC *)); /* function to call */
GENERIC p; /* and parameter */
int when; /* number of chunks to let go before calling */
}
*start, /* what still to output */
*end; /* where to add new tags */
/* flush_tags: use tags that have gone by recently */
LOCAL void flush_tags()
{
ioctl(audio, AUDIO_GETINFO, &ainfo);
if (start)
{
while (start && start->when <= ainfo.play.eof + ADVANCE_TAGS)
{
struct tagged *tofree;
(*start->f)(start->p);
tofree = start;
start = start->next;
free(tofree);
}
}
}
/* remove unused tags at end */
LOCAL void remove_pending_tags()
{
while (start)
{
struct tagged *tofree;
tofree = start;
start = start->next;
free(tofree);
}
}
void sync_audio(function, parameter)
void (*function) P((void *));
GENERIC parameter;
{
struct tagged *t;
t = malloc(sizeof(struct tagged));
if (!t)
{
(*function)(parameter);
return;
}
/* build new tag */
t->next = 0;
t->f = function;
t->p = parameter;
t->when = written;
/* add it to list */
if (start)
end->next = t;
else
start = t;
end = t;
/* set up for next tag */
write(audio, buffer, 0);
written++;
if (!tsync)
flush_tags();
}
void flush_buffer()
{
int actual;
int number;
actual = write(audio, buffer, dsize * idx);
if (actual == -1)
notice("Write to audio failed");
else if (actual != dsize * idx)
notice("Short write to audio");
if (wait_samples)
{ /* currently paused ? */
wait_samples -= actual;
if (wait_samples <= 0)
{ /* right number of samples gone by ? */
wait_samples = 0;
ainfo2.play.pause = FALSE;
ioctl(audio, AUDIO_SETINFO, &ainfo2);
}
}
if (tsync)
flush_tags();
idx = 0;
}
void discard_buffer()
{
remove_pending_tags();
ioctl(audio, I_FLUSH, FLUSHW);
if (wait_samples)
{
ainfo2.play.pause = FALSE;
ioctl(audio, AUDIO_SETINFO, &ainfo2);
wait_samples = 0;
}
set_synchronize();
}
void close_audio()
{
remove_pending_tags();
free(buffer);
close(audio);
}
int output_resolution()
{
return 16;
}